﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using ShevaEngine.Core.Foundation;
using ShevaEngine.Core.Modules.ArtificialIntelligence.Pathfinding;

namespace PathfindingTest
{
    /// <summary>
    /// Main form.
    /// </summary>
    public partial class MainForm : Form
    {
        /// <summary>Navigation graph.</summary>
        public NavigationGraph NavigationGraph;
        /// <summary>Timer.</summary>
        private Timer Timer;
        /// <summary>Previous time.</summary>
        private DateTime PreviousTime;
        /// <summary>Person.</summary>
        private Actor Person;

        /// <summary>
        /// Constructor.
        /// </summary>
        public MainForm()
        {
            this.InitializeComponent();

            this.CreateGraph();

            this.CreateEntities();

            this.PreviousTime = DateTime.Now;

            this.Timer = new Timer();
            this.Timer.Interval = 30;
            this.Timer.Tick += new EventHandler(this.Update);
            this.Timer.Start();            
        }

        /// <summary>
        /// Update method.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Update(object sender, EventArgs e)
        {
            DateTime nowTime = DateTime.Now;

            TimeSpan time = nowTime - this.PreviousTime;            

            this.PreviousTime = nowTime;

            this.EntityManager.Update(new GameTime(time, time));
            this.Invalidate();
        }

        /// <summary>
        /// Method creates navigation graph.
        /// </summary>
        private void CreateGraph()
        {
            List<Pair<Int32, Int32>> cells = new List<Pair<int, int>>();

            Int32[][] level = new Int32[][] {
                new Int32[] {1,1,1,1,0,0,0,0,0,0,0,0},
                new Int32[] {1,1,1,1,1,1,1,0,0,0,0,1},
                new Int32[] {0,0,1,1,0,0,1,0,0,0,0,1},
                new Int32[] {1,0,1,1,0,0,1,1,0,1,1,1},
                new Int32[] {1,0,1,1,0,0,0,0,1,0,0,1},
                new Int32[] {1,0,0,1,1,1,1,1,1,1,1,1},
                new Int32[] {1,0,0,0,0,0,0,0,0,0,0,1},
                new Int32[] {1,1,1,1,1,1,1,1,1,1,1,1},
            };

            for (int iRow = 0; iRow < level.Length; iRow++)
                for (int iCol = 0; iCol < level[iRow].Length; iCol++)
                    if (level[iRow][iCol] == 1)
                        cells.Add(new Pair<int, int>(iCol + 1, iRow + 1));

            this.NavigationGraph = NavigationGraph.CreateFromRegularGrid(cells, 30);            
        }

        /// <summary>
        /// Method creates entity manager a entities.
        /// </summary>
        public void CreateEntities()
        {
            this.EntityManager = new EntityManager();

            this.Person = new Person(Matrix.CreateTranslation(30, 0, 30));

            this.EntityManager.RegisterEntity(this.Person);

            Entity newEntity = new Person(Matrix.CreateTranslation(25, 0, 30));
            this.EntityManager.RegisterEntity(newEntity);
            newEntity.Task = new FollowTask(newEntity, this.NavigationGraph, this.Person, 5);

            //person.Task = new MoveToTask(person, this.NavigationGraph, new Vector3(120, 0, 180));            
        }

        /// <summary>
        /// Overriding paint method.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            g.ScaleTransform(1, -1);
            g.TranslateTransform(0, -this.ClientRectangle.Height);

            foreach (NavigationGraphNode node in this.NavigationGraph.Nodes)
            {
                List<Vector3> borderVertices = node.GetBorderVertices();

                List<PointF> lines = new List<PointF>();
                
                for (int i = 0; i < borderVertices.Count; i++)
                {
                    lines.Add(new PointF(borderVertices[i].X, borderVertices[i].Z));
                    lines.Add(new PointF(borderVertices[(i + 1) % borderVertices.Count].X, borderVertices[(i + 1) % borderVertices.Count].Z));
                }

                g.DrawLines(Pens.Red, lines.ToArray());

                //List<PointF> connectionLines = new List<PointF>();

                //foreach (NavigationGraphConnection connection in node.Connections)
                //{
                //    connectionLines.Add(new PointF((node as NavigationGraphNodeQuad2D).Quad.Center.X, (node as NavigationGraphNodeQuad2D).Quad.Center.Z));

                //    if (connection.Node1 == node)
                //        connectionLines.Add(new PointF((connection.Node2 as NavigationGraphNodeQuad2D).Quad.Center.X, 
                //            (connection.Node2 as NavigationGraphNodeQuad2D).Quad.Center.Z));
                //    else
                //        connectionLines.Add(new PointF((connection.Node1 as NavigationGraphNodeQuad2D).Quad.Center.X,
                //            (connection.Node1 as NavigationGraphNodeQuad2D).Quad.Center.Z));
                //}

                //if (connectionLines.Count > 0)
                //    g.DrawLines(Pens.Blue, connectionLines.ToArray());
            }


            List<PointF> pathLines = new List<PointF>();

            if (this.Person != null && this.Person.Task is MoveToTask && (this.Person.Task as MoveToTask).NavigationPath.Count > 1)
            {
                foreach (NavigationGraphConnection connection in (this.Person.Task as MoveToTask).NavigationPath)
                    pathLines.Add(new PointF(connection.Center.X, connection.Center.Z));
                
                g.DrawLines(Pens.Green, pathLines.ToArray());
            }

            foreach (Entity entity in this.EntityManager.LocalEntities)
            {
                g.DrawEllipse(Pens.Blue, entity.World.Translation.X - 5, entity.World.Translation.Z - 5, 10, 10);

                Vector3 vector = Vector3.Transform(Vector3.UnitX * 10, entity.World);

                g.DrawLine(Pens.Blue, new PointF(entity.World.Translation.X, entity.World.Translation.Z),
                    new PointF(vector.X, vector.Z));
            }
        }
        
        /// <summary>
        /// On mouse click event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_MouseClick(object sender, MouseEventArgs e)
        {
            this.Person.Task = new MoveToTask(this.Person, this.NavigationGraph, new Vector3(e.X, 0, (this.ClientRectangle.Height - e.Y)));
        }
    }
}
